import { formatToken, getToken } from "@/utils/auth";
import Axios, { type AxiosInstance, type AxiosRequestConfig } from "axios";
import NProgress from "../progress";
import type { PureHttpError, PureHttpRequestConfig, PureHttpResponse, RequestMethods } from "./types.d";
// import { useUserStoreHook } from "@/store/modules/user";
import { removeToken } from "@/utils/auth";
import { logout } from "@/utils/logout";
import { PxMessage } from "px-ui";
import { axiosTimeout as timeout } from "./constant";

const { VITE_API_URL: proxy_url = "/" } = import.meta.env;
let tokenExpire = false; // token失效标记

// 相关配置请参考：www.axios-js.com/zh-cn/docs/#axios-request-config-1
const defaultConfig: AxiosRequestConfig = {
  baseURL: proxy_url,
  timeout,
  headers: {
    Accept: "application/json, text/plain, */*",
    "Content-Type": "application/json",
    "X-Requested-With": "XMLHttpRequest"
  }
};

class PureHttp {
  constructor() {
    this.httpInterceptorsRequest();
    this.httpInterceptorsResponse();
  }

  /** token过期后，暂存待执行的请求 */
  private static requests = [];

  /** 初始化配置对象 */
  private static initConfig: PureHttpRequestConfig = {};

  /** 保存当前Axios实例对象 */
  private static axiosInstance: AxiosInstance = Axios.create(defaultConfig);

  /** 请求拦截 */
  private httpInterceptorsRequest(): void {
    PureHttp.axiosInstance.interceptors.request.use(
      async (config: PureHttpRequestConfig): Promise<any> => {
        // 开启进度条动画
        NProgress.start();
        // 优先判断post/get等方法是否传入回调，否则执行初始化设置等回调
        if (typeof config.beforeRequestCallback === "function") {
          config.beforeRequestCallback(config);
          return config;
        }
        if (PureHttp.initConfig.beforeRequestCallback) {
          PureHttp.initConfig.beforeRequestCallback(config);
          return config;
        }
        /** 请求白名单，放置一些不需要token的接口（通过设置请求白名单，防止token过期后再请求造成的死循环问题） */
        const whiteList = [""];
        return whiteList.find(url => url === config.url)
          ? config
          : new Promise(resolve => {
              const data = getToken();
              if (data) {
                config.headers["Authorization"] = formatToken(data.accessToken);
                // 全局通用axios配置header头添加facCode
                const facCode = localStorage.getItem("facCode");
                config.headers["facCode"] = facCode;
                resolve(config);
              } else {
                resolve(config);
              }
            });
      },
      error => {
        return Promise.reject(error);
      }
    );
  }

  /** 响应拦截 */
  private httpInterceptorsResponse(): void {
    const instance = PureHttp.axiosInstance;
    instance.interceptors.response.use(
      (response: PureHttpResponse) => {
        const $config = response.config;
        // 关闭进度条动画
        NProgress.done();
        // pms 接口校验
        if (response.data?.code === 200 || response.data?.msg === "success") {
          return response.data.data;
        }
        // token失效状态码1005,uac的token失效401、在其它地方登录40100，登录已过期40101
        if (
          response.data.code == "1004" ||
          response.data.code == "1005" ||
          response.data.code == "401" ||
          response.data.code == "40100" ||
          response.data.code == "40101"
        ) {
          if (tokenExpire) return;
          // useUserStoreHook().logOut();
          // PxMessage.error(response.data.msg);
          PxMessage.error({
            message: response.data.msg,
            onClose: () => {
              logout();
              tokenExpire = true;
            },
            duration: 2000
          });
          return;
        }
        /**
         * 0001 账户不存在！
         * 0002 账户未登录
         * 0003 登出成功！
         * 0004 账户登录失败，请重试！
         * 0008 账户校验完成！
         */
        if (response.data.code == "0001" || response.data.code == "0004") {
          PxMessage.error({
            message: response.data.msg,
            onClose: () => {
              logout();
            },
            duration: 2000
          });
          return;
        }

        if (response.data.code == "0002" || response.data.code == "0003") {
          if (response.data.data) {
            removeToken();
            window.location.replace(response.data.data);
          }
          return;
        } else if (response.data.code == "0008") {
          if (response.data.data) {
            window.location.replace(response.data.data);
          }
          return;
        }

        if (!response.data.success) {
          PxMessage.error(response.data.msg);
          return Promise.reject(response.data);
        }
        // 优先判断post/get等方法是否传入回调，否则执行初始化设置等回调
        if (typeof $config.beforeResponseCallback === "function") {
          $config.beforeResponseCallback(response);
          return response.data.data;
        }
        if (PureHttp.initConfig.beforeResponseCallback) {
          PureHttp.initConfig.beforeResponseCallback(response);
          return response.data.data;
        }
        tokenExpire = false;
        return response.data.data;
      },
      (error: PureHttpError) => {
        NProgress.done();
        error?.message && PxMessage.error(`${error?.name || ""} : ${error?.message || ""}`);
        const $error = error;
        $error.isCancelRequest = Axios.isCancel($error);
        return Promise.reject($error);
      }
    );
  }

  /** 通用请求工具函数 */
  public request<T>(
    method: RequestMethods,
    url: string,
    param?: AxiosRequestConfig,
    axiosConfig?: PureHttpRequestConfig,
    errCallBack?: (err: any) => any
  ): Promise<T> {
    const config = {
      method,
      url,
      ...param,
      ...axiosConfig
    } as PureHttpRequestConfig;

    // 单独处理自定义请求/响应回调
    return new Promise((resolve, reject) => {
      PureHttp.axiosInstance
        .request(config)
        .then((response: undefined) => {
          resolve(response);
        })
        .catch(error => {
          errCallBack && errCallBack(error);
          reject(error);
        });
    });
  }

  /** 单独抽离的post工具函数 */
  public post<T, P>(url: string, params?: AxiosRequestConfig<T>, config?: PureHttpRequestConfig): Promise<P> {
    return this.request<P>("post", url, params, config);
  }

  /** 单独抽离的get工具函数 */
  public get<T, P>(url: string, params?: AxiosRequestConfig<T>, config?: PureHttpRequestConfig): Promise<P> {
    return this.request<P>("get", url, params, config);
  }
}

export const http = new PureHttp();
